#include <iostream>
#include <string>
#include "TcpServer.hpp"
#include <memory>
#include "Protocol.hpp"
#include "LockGuard.hpp"
#include "Log.hpp"
#include <functional>
#include "CalCulate.hpp"
#include <unistd.h>

using namespace protocol_ns;

using callback_t = std::function<Response(const Request &)>;

class CalService
{
public:
    CalService(callback_t cb)
        : _cb(cb)
    {
    }
    // 每个客户端跑的函数
    void service(socket_sptr fd, InetAddr client)
    {
        int sockfd = fd->SockFd();
        LOG(DEBUG, "get a new link, info %s:%d, fd : %d\n", client.Ip().c_str(), client.Port(), sockfd);
        std::string clientaddr = "[" + client.Ip() + ":" + std::to_string(client.Port()) + "]# ";
        std::string inbuffer;
        while (true)
        {
            sleep(5); // 5秒后开始Recv

            Request req;
            int n = fd->Recv(&inbuffer);
            if (n < 0)
            {
                LOG(DEBUG, "%s quit....\n", clientaddr);
                break;
            }
            // 对面可能一次性发了太多报文拼接成的大报文，所以我要while不断截取直到截取不出来完整报文，再继续Recv
            std::string packstr;
            while (true)
            {
                // 读到的inbuffer不一定是完整的报文
                std::cout << "inbuffer: " << inbuffer << std::endl;
                packstr = DeCode(inbuffer);
                if (packstr.empty())
                    break;
                // 否则，一定截取出来的是完整的报文, 并且返回值是有效载荷
                std::cout << "------------------------begin---------------" << std::endl;
                std::cout << "resq string:\n"
                          << packstr << std::endl;
                // 反序列化  到Request结构化数据里面
                req.Deserialize(packstr);

                // 业务处理
                Response res = _cb(req);

                // 序列化，发回去
                std::string send_str;
                res.Serialize(&send_str);
                std::cout << "resp Serialize:" << std::endl;
                std::cout << send_str << std::endl;

                // 添加报头
                send_str = EnCode(send_str);
                std::cout << "resp Encode:" << std::endl;
                std::cout << send_str << std::endl;
                // 发送
                int n = fd->Send(send_str); // 信息处理， epoll
            }
        }
    }

private:
    callback_t _cb;
};

void Usage(std::string proc)
{
    std::cout << "Usage: " << proc << " serverport" << std::endl;
}

// tcpserver  port
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(USAGE_ERROR);
    }
    uint16_t port = std::stoi(argv[1]);
    EnableScreen();
    //2. 部署到服务器，日志到文件方案---------------------------------------------------------------------------------------------------------
    // 从此刻开始服务端变成守护进程，新开会话，部署到服务器
    //daemon(0, 0);

    //EnableFile();
    CalCulate cal;
    CalService calservice(std::bind(&CalCulate::Excute, &cal, std::placeholders::_1));
    io_service_t service = std::bind(&CalService::service, &calservice, std::placeholders::_1, std::placeholders::_2);
    std::unique_ptr<TcpServer> tsvr = std::make_unique<TcpServer>(port, service);
    tsvr->Loop();
    return 0;
}